package com.wh1200.mybatis.xmlless.util

import com.wh1200.kotlin.toWords
import com.wh1200.mybatis.xmlless.ElementInfoBuilder
import com.wh1200.mybatis.xmlless.enums.Operations
import com.wh1200.mybatis.xmlless.enums.XmllessDbType
import com.wh1200.mybatis.xmlless.inter.ITypeResolver
import com.wh1200.mybatis.xmlless.model.ClassInfo
import com.wh1200.mybatis.xmlless.model.MethodInfoWrapper
import com.wh1200.mybatis.xmlless.model.ResolvedQuery
import com.wh1200.mybatis.xmlless.resolver.MappingResolver
import com.wh1200.mybatis.xmlless.resolver.TypeResolver
import org.apache.ibatis.mapping.MappedStatement
import java.lang.reflect.Method
import java.util.concurrent.ConcurrentHashMap
import kotlin.contracts.contract

@OptIn(kotlin.contracts.ExperimentalContracts::class)
inline fun <reified R> Any?.checkType(): Boolean {
  contract { returns() implies (this@checkType is R) }
  return this is R
}

data class OperationName(val op: Operations, val words: List<String>)

fun operationsNameWords(): List<OperationName> {
  return Operations.values().map {
    OperationName(it, it.name.toWords())
  } + Operations.values().map { OperationName(it, listOf(it.name.toWords().joinToString(""))) } +
      Operations.values().filter { it.name.toWords().size == 1 }.map {
        OperationName(it, it.name.toWords().map { it.uppercase() })
      }
}


/**
 *
 * @author 吴昊
 * @date 2023/12/16 21:18
 * @since v4.0.0
 * @version 1.0
 */
object XmllessInfoUtil {

  private val RESOLVED_METHODS = mutableMapOf<String, Boolean>()
  private val ENTITY_MAP_IDS = ConcurrentHashMap<String, MethodInfoWrapper>()

  fun addResolvedQuery(resolvedQuery: ResolvedQuery) {
    RESOLVED_METHODS[resolvedQuery.methodInfo.fullMethodName] = true
  }

  fun isXmllessResolvedMethod(method: Method): Boolean {
    return RESOLVED_METHODS.containsKey(method.declaringClass.name + "." + method.name)
  }

  fun isXmllessResolvedMethod(id: String): Boolean {
    return RESOLVED_METHODS.containsKey(id)
  }

  fun setDbType(dbType: XmllessDbType) {
    DbTypeHolder.setDbType(dbType)
  }

  fun isMapToEntityMethod(ms: MappedStatement): Boolean {
    return ENTITY_MAP_IDS.containsKey(ms.id)
  }

  @Synchronized
  fun addMapToEntityMethod(id: String, mapper: Class<*>, method: Method) {
    ENTITY_MAP_IDS[id] = MethodInfoWrapper(mapper, method)
  }

  fun registerTypeResolver(springTypeResolver: ITypeResolver) {
    TypeResolver.registerResolver(springTypeResolver)
  }

  fun clearCache() {
    TableInfoProvider.clearCache()
    ElementInfoBuilder.clearCache()
    MappingResolver.clearCache()
    ClassInfo.clearCache()
  }

}
